/**
 * Filename: GlobeViewSwitchView.java
 * @author  Firefly
 * @contact postfirefly@163.com
 * @time    2016/4/25 16:54
 */
package com.github.postsanf.yinian.view;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.ListIterator;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.widget.RelativeLayout;

@SuppressLint("NewApi")
public class GlobeViewSwitchView extends RelativeLayout{
    private Context mContext;						    // 上下文
    private GestureDetector mGestureDetector; 		    // 手势操作
    private float angle;							    // 旋转的角度
    private List<View> views = new ArrayList<View>();   	// 子View列表
    private int size = 3; 								// 子控件个数
    private OnItemClickListener mItemClickListener;
    private OnAlbumSelcetListener mAlbumSelcetListener;
    private OnLoopViewTouchListener mLoopViewTouchListener;
    private boolean isCanCilckListener = false;  	    // 是否可以点击
    private int selectPosition; 					    // 当前选中的Ttem位置
    private float last_angle; 						    // 最后的角度，用来记录上一次取消touch之后的角度
    private final static int LoopR = 200;
    private float r =  LoopR;
    private float multiple = .85f; 					    // 倍数，view之间的比例
    private float distance = multiple * r;  		    // 子View之间的距离
    private boolean touching = false;				    // 判断是否手指在touch
    private float distancY ;						    // 在y轴上边移动的距离
    private float limitY = 30; 						    // 滑动的阈值，用来判断能不能点击

    private ValueAnimator restAnimator = null;		    // 复位动画
    private ValueAnimator roAnimator = null;		    // 旋转动画
    private boolean isAuto = false;
    private boolean isLeftToRightScroll = true; 	    // 默认自动滚动是否是从右往左

    private AutoScrollHandler mHandler = new AutoScrollHandler(){
        void scroll() {
            if (size != 0) {                            // 判断自动滑动从哪边开始
                int perAngle = 0;
                if (isLeftToRightScroll) {
                    perAngle = 360 /size;
                }else {
                    perAngle = -360/size;
                }
                if (angle == 360) {
                    angle = 0f;
                }
                AnimRotationTo(angle + perAngle, null);
            }
        };
    };

    public GlobeViewSwitchView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    public GlobeViewSwitchView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public GlobeViewSwitchView(Context context) {
        super(context);
        init(context);
    }

    // 初始化并创建手势对象
    public void init(Context context){
        this.mContext = context;
        mGestureDetector = new GestureDetector(mContext, getGestureController());
    }

    private GestureDetector.SimpleOnGestureListener getGestureController(){
        return new GestureDetector.SimpleOnGestureListener(){
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2,
                                    float distanceX, float distanceY){
                // 与Y轴夹角大于30°或Y轴移动不超过8 则响应子View
                if (1.732*Math.abs(distanceX) >= Math.abs(distanceY) || Math.abs(distanceY)<8){
                    return true;
                } else {
                    // 计算滑动的角度
                    angle += distanceY/views.size();
                    initView();
                    return false;
                }
            }
        };
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        mGestureDetector.onTouchEvent(event);
        return false;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 进行控件界面的初始化
        initView();
        if (isAuto) {
            mHandler.sendEmptyMessageDelayed(AutoScrollHandler.messageId, mHandler.scroll_interval);
        }
    }
    private void initView() {
        int width = getWidth();
//            case 1:
//                ViewGroup.LayoutParams mm = views.get(0).getLayoutParams();
//                mm.height = getHeight();
//                mm.width  = getWidth();
//                views.get(0).setLayoutParams(mm);
//                views.get(0).setX(width / 2  - views.get(0).getWidth() / 2); //设置他的坐标
//                views.get(0).setY(width / 2  - views.get(0).getWidth() / 2);
        for (int i = 0; i < views.size(); i++) {
                float x0 = (float)Math.sin(Math.toRadians(angle  + 250 - i * 360 / size)) * r;
                float y0 = (float)(Math.cos(Math.toRadians(angle + 250 - i * 360 / size)) * 1.2f * r);
                float scale0 = (distance - x0) / (distance + r);
                ViewGroup.LayoutParams m = views.get(i).getLayoutParams();
                m.height =  getHeight();
                m.width  =  getWidth();
                views.get(i).setLayoutParams(m);
                views.get(i).setScaleX(scale0);
                views.get(i).setScaleY(scale0);
                views.get(i).setX(width / 2 + x0 - views.get(i).getWidth() / 2 + r * 19/20);
                views.get(i).setY(width / 2 - y0*4/5  - views.get(i).getWidth() * 2/3);
        }

        List<View> arr = new ArrayList<View>();
        for (int i = 0; i < views.size(); i++){
            arr.add(views.get(i));
            views.get(i).setTag(i);
        }
        sortList(arr);
        // 刷新界面，重新排布
        postInvalidate();
    }

    @SuppressWarnings("unchecked")
    private <T> void sortList(List<View> arr) {
        @SuppressWarnings("rawtypes")
        Comparator comparator = new SortComparator();
        T[] array = arr.toArray((T[]) new Object[arr.size()]);

        Arrays.sort(array, comparator);
        int i = 0;
        ListIterator<T> it = (ListIterator<T>) arr.listIterator();
        while (it.hasNext()) {
            it.next();
            it.set(array[i++]);
        }
        for (int j = 0; j < arr.size(); j++) {
            arr.get(j).bringToFront();
        }
    }

    /**
     * 设置布局的宽高，并策略menu item宽高
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        //对容器中的子view放置位置
        if (changed) {
            checkChildView();
            if (mAlbumSelcetListener != null) {
                isCanCilckListener = true;
                int pos = selectPosition>= 0 ? selectPosition : 3 + selectPosition;
                mAlbumSelcetListener.onSelect((int) (angle/120), views.get(pos));
            }
            Ranimation();//子view初始化动画
        }
    }

    public void Ranimation(){
        Ranimation(1f, r);
    }
    public void Ranimation(boolean fromZeroToR){
        if (fromZeroToR) {
            Ranimation(1f, LoopR);
        }else {
            Ranimation(LoopR, 1f);
        }
    }
    public void Ranimation(float from, float to) {
        roAnimator = ValueAnimator.ofFloat(from,to);
        roAnimator.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                r = (Float)animation.getAnimatedValue();
                initView();
            }
        });

        roAnimator.setInterpolator(new DecelerateInterpolator());
        roAnimator.setDuration(2000);
        roAnimator.start();
    }

    //　获取子view并添加点击事件
    public void checkChildView(){
        for (int i = 0; i < views.size(); i++) {//先清空views里边可能存在的view防止重复
            views.remove(i);
        }
        final int count = getChildCount();//获取子View的个数
        size = count;
        for (int i = 0; i < count; i++) {
            View view = getChildAt(i); //获取指定的子view
            final int position =  i;
                views.add(view);
                view.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //对子view添加点击事件
                        if (position != calculateItem()){
                            setSelectItem(position);
                        }else {
                            if (isCanCilckListener && mItemClickListener != null) {
                                mItemClickListener.onItemClick(position, views.get(position));
                            }
                        }
                    }
                });
            }
    }
    /**
     * 设置所选中的item
     * @param selectItem
     */
    public void setSelectItem(int selectItem){
        if (selectItem >= 0) {
            float corner = 0;
            if (getSelectPosition() == 0) {
                if (selectItem == views.size() - 1){
                    corner = angle - (360 / size);
                }else{
                    corner = angle + (360 / size);
                }
            }else if (getSelectPosition() == views.size() - 1){
                if (selectItem == 0) {
                    corner = angle + (360 / size);
                }else {
                    corner = angle - (360 /size);
                }
            }else{
                if (selectItem > getSelectPosition()){
                    corner = angle +(360 /size);
                }else{
                    corner = angle - (360 /size);
                }
            }

            float position = 0 ;
            float per = 360 /size;
            if (corner < 0) {
                per = -per;
            }

            float minValue = (int)(corner /per) * per;
            float maxValue = (int)(corner / per) * per;
            if (corner >= 0) {
                if (corner - last_angle > 0) {
                    position = maxValue;
                }else {
                    position = minValue;
                }
            }else {
                if (corner - last_angle < 0) {
                    position = maxValue;
                }else {
                    position = minValue;
                }
            }
            if (size > 0) {//旋转动画
                AnimRotationTo(position, null);
            }
        }
    }
    public float getAngle() {
        return angle;
    }
    public void setAngle(float angle) {
        this.angle = angle;
    }
    public void setmItemClickListener(OnItemClickListener mItemClickListener) {
        this.mItemClickListener = mItemClickListener;
    }
    public void setmAlbumSelcetListener(OnAlbumSelcetListener mAlbumSelcetListener) {
        this.mAlbumSelcetListener = mAlbumSelcetListener;
    }
    public void setmLoopViewTouchListener(
            OnLoopViewTouchListener mLoopViewTouchListener) {
        this.mLoopViewTouchListener = mLoopViewTouchListener;
    }
    /**
     * 计算现在选中item
     * @return
     */
    public int calculateItem(){
        float cor = Math.abs(angle % 360);
        if(cor <= 60 || cor >= 300){
            return 0;
        }else if(cor > 60 && cor <= 180){
            return (angle > 0 ? 1 : -2);
        }else{
            return (angle > 0 ? 2 : -1);
        }
    }

    public int getSelectPosition() {
        return selectPosition;
    }

    public float getR() {
        return r;
    }
    public GlobeViewSwitchView setR(float r) {
        this.r = r;
        distance = multiple * r;
        return this;

    }
    private  boolean onTouch(MotionEvent event){
        if (event.getAction() == MotionEvent.ACTION_DOWN){
            last_angle = angle ;
            touching = true;
        }

        if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
            touching = false;
            restPosition();
            return true;
        }
        return true;
    }

    public void setCurDegree(int num){
        setAngle(num*360/size);
        restPosition();
    }

    private void restPosition() {
        if (size == 0) {
            return ;
        }

        float position = 0;
        float per = 360 /size;
        if (angle < 0) {
            per = -per;
        }

        float minValue = (int)(angle / per) * per;
        float maxValue = (int)(angle / per) * per + per;
        if (angle > 0) {
            if (angle -last_angle > 0){
                position = maxValue;
            }else {
                position = minValue;
            }
        }else {
            if (angle - last_angle > 0){
                position  = angle == last_angle ? maxValue : minValue ;
            }else {
                position = angle == last_angle ? minValue : maxValue;
            }
        }
        AnimRotationTo(position,null);
    }

    private void AnimRotationTo(float position, final Runnable runnable){
        if (angle == position) {//如果相同说明不需要旋转
            return;
        }
        restAnimator = ValueAnimator.ofFloat(angle,position);
        restAnimator.setInterpolator(new DecelerateInterpolator());//设置旋转减速插值器
        restAnimator.setDuration(300);
        restAnimator.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                if (touching == false) {
                    angle = (Float)animation.getAnimatedValue();
                    initView();
                }
            }
        });

        restAnimator.addListener(new AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }
            @Override
            public void onAnimationRepeat(Animator animation) {

            }
            @Override
            public void onAnimationEnd(Animator animation) {
                if (touching == false) {
                    selectPosition = calculateItem();
                }
                if (mAlbumSelcetListener != null) {
                    int pos = selectPosition>= 0 ? selectPosition : 3 + selectPosition;
                    mAlbumSelcetListener.onSelect((int) (angle/120), views.get(pos));
                }
            }
            @Override
            public void onAnimationCancel(Animator animation) {

            }
        });

        if (runnable != null) {
            restAnimator.addListener(new AnimatorListener() {

                @Override
                public void onAnimationStart(Animator animation) {

                }

                @Override
                public void onAnimationRepeat(Animator animation) {

                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    runnable.run();
                }

                @Override
                public void onAnimationCancel(Animator animation) {
                }
            });
        }
        restAnimator.start();

    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mLoopViewTouchListener != null) {
            mLoopViewTouchListener.onTouch(event);
        }
        isCanClickListener(event);
        return true;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        onTouch(ev);
        if (mLoopViewTouchListener != null) {
            mLoopViewTouchListener.onTouch(ev);
        }
        isCanClickListener(ev);
        return super.dispatchTouchEvent(ev);
    }

    public void isCanClickListener(MotionEvent event){
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                distancY = event.getY();
                if (isAuto) {
                    mHandler.removeMessages(AutoScrollHandler.messageId);
                }
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                if (isAuto) {
                    mHandler.sendEmptyMessageDelayed(AutoScrollHandler.messageId,  mHandler.scroll_interval);
                }
                if (event.getY() - distancY > limitY || distancY - event.getY() > limitY) {
                    isCanCilckListener = false;
                }else{
                    isCanCilckListener = true;
                }
                break;
            case MotionEvent.ACTION_MOVE:

                break;
            default:
                break;
        }
    }

    public void setAuto(boolean isAuto) {
        this.isAuto = isAuto;
    }

    public void setLeftScroll(boolean isLeftToRightScroll){
        this.isLeftToRightScroll = isLeftToRightScroll;
    }

    public void setScrollInterval(long time){
        if (mHandler != null) {
            mHandler.setScroll_interval(time);
        }
    }
}
